﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace MyLib.Web.UI {
	/// <summary>
	/// 
	/// </summary>
	[ParseChildren(true, "Items")]
	public abstract class MyListControl : DataBoundControl, INamingContainer {
		/// <summary>
		/// 
		/// </summary>
		private const string MultiValueSeparator = ",";

		private string m_cachedSelectedValue;

		private Style m_itemStyle;

		private List<MyListItem> m_items;

		/// <summary>
		/// 
		/// </summary>
		[Description("MyCheckBoxList_ItemStyle"),
		NotifyParentProperty(true),
		Category("Styles"), DefaultValue((string)null),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
		PersistenceMode(PersistenceMode.InnerProperty)]
		public Style ItemStyle {
			get {
				if (this.m_itemStyle == null) {
					this.m_itemStyle = new Style();
					if (base.IsTrackingViewState) {
						((IStateManager)this.m_itemStyle).TrackViewState();
					}
				}
				return this.m_itemStyle;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		protected override HtmlTextWriterTag TagKey {
			get {
				return HtmlTextWriterTag.Div;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[DefaultValue(null),
		MergableProperty(false),
		Category("Default"),
		Description("ListControl_Items")]
		public List<MyListItem> Items {
			get {
				if (m_items == null) {
					m_items = new List<MyListItem>();
				}

				return m_items;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[DefaultValue(""), Category("Data"), Description("MyListControl_DataTextField"), Themeable(false)]
		public virtual string DataTextField {
			get {
				object obj2 = this.ViewState["DataTextField"];
				if (obj2 != null) {
					return (string)obj2;
				}
				return string.Empty;
			}
			set {
				this.ViewState["DataTextField"] = value;
				if (base.Initialized) {
					base.RequiresDataBinding = true;
				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[DefaultValue(""), Themeable(false), Category("Data"), Description("MyListControl_DataValueField")]
		public virtual string DataValueField {
			get {
				object obj2 = this.ViewState["DataValueField"];
				if (obj2 != null) {
					return (string)obj2;
				}
				return string.Empty;
			}
			set {
				this.ViewState["DataValueField"] = value;
				if (base.Initialized) {
					base.RequiresDataBinding = true;
				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[DefaultValue(false), Themeable(false), Category("Behavior"), Description("MyListControl_ShowUnselected")]
		public virtual bool ShowUnselected {
			get {
				object obj2 = this.ViewState["ShowUnselected"];
				if (obj2 != null) {
					return (bool)obj2;
				}
				return false;
			}
			set {
				this.ViewState["ShowUnselected"] = value;
				if (base.Initialized) {
					base.RequiresDataBinding = true;
				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[DefaultValue(""), Themeable(false), Category("Data"), Description("MyListControl_DataGroupField")]
		public virtual string DataGroupField {
			get {
				object obj2 = this.ViewState["DataGroupField"];
				if (obj2 != null) {
					return (string)obj2;
				}
				return string.Empty;
			}
			set {
				this.ViewState["DataGroupField"] = value;
				if (base.Initialized) {
					base.RequiresDataBinding = true;
				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[DefaultValue(""), Themeable(false), Category("Data"), Description("MyListControl_DataTooltipField")]
		public virtual string DataTooltipField {
			get {
				object obj2 = this.ViewState["DataTooltipField"];
				if (obj2 != null) {
					return (string)obj2;
				}
				return string.Empty;
			}
			set {
				this.ViewState["DataTooltipField"] = value;
				if (base.Initialized) {
					base.RequiresDataBinding = true;
				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[DefaultValue(""), Themeable(false), Category("Data"), Description("MyListControl_DataTextFormatString")]
		public virtual string DataTextFormatString {
			get {
				object obj2 = this.ViewState["DataTextFormatString"];
				if (obj2 != null) {
					return (string)obj2;
				}
				return string.Empty;
			}
			set {
				this.ViewState["DataTextFormatString"] = value;
				if (base.Initialized) {
					base.RequiresDataBinding = true;
				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[Bindable(true, BindingDirection.TwoWay)]
		public virtual string SelectedValue {
			get {
				return string.Join(",", this.Items
					.Where(_ => _.Selected)
					.Select(_ => _.Value));
			}
			set {
				if (this.Items.Count == 0) {
					m_cachedSelectedValue = value;
					return;
				}

				if ((value == null) || (base.DesignMode && (value.Length == 0))) {
					this.ClearSelection();
					return;
				}

				SetSelectedValue(value);

				m_cachedSelectedValue = value;
			}
		} // end of SelectedValue.

		/// <summary>
		/// 
		/// </summary>
		[DefaultValue(false), Category("Behavior"), Description("MyListControl_AutoPostBack"), Themeable(false)]
		public virtual bool AutoPostBack {
			get {
				object obj2 = this.ViewState["AutoPostBack"];
				return ((obj2 != null) && ((bool)obj2));
			}
			set {
				this.ViewState["AutoPostBack"] = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public virtual void ClearSelection() {
			for (int i = 0; i < this.Items.Count; i++) {
				this.Items[i].Selected = false;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="value"></param>
		protected virtual void SetSelectedValue(string value) {
			var values = value.Split(new string[] { MultiValueSeparator }, StringSplitOptions.None);

			if (values != null && values.Length != 0) {
				this.ClearSelection();

				foreach (var item in this.Items) {
					item.Selected = values.Contains(item.Value);
				}
			}
		} // end of SetSelectedValue.

		/// <summary>
		/// 
		/// </summary>
		/// <param name="dataSource"></param>
		protected override void PerformDataBinding(IEnumerable dataSource) {
			// Clear all existing items.
			this.Items.Clear();

			if (dataSource != null) {
				ICollection is2 = dataSource as ICollection;
				if (is2 != null) {
					this.Items.Capacity = is2.Count;
				}

				var index = 0;
				foreach (object obj2 in dataSource) {
					var item = CreateListItem(obj2, index++);

					this.Items.Add(item);
				}
			}
			if (this.m_cachedSelectedValue != null) {
				SetSelectedValue(this.m_cachedSelectedValue);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="savedState"></param>
		protected override void LoadViewState(object savedState) {
			// Clear all existing items.
			this.Items.Clear();

			if (savedState != null) {
				Pair pair = (Pair)savedState;
				base.LoadViewState(pair.First);

				var list = (List<object>)pair.Second;
				
				for (int i = 0; i < list.Count; ++i) {
					var nitem = new MyListItem(0);
					((IStateManager)nitem).LoadViewState(list[i]);
					Items.Add(nitem);
				}
			} else {
				base.LoadViewState(null);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		protected override object SaveViewState() {
			object x = base.SaveViewState();
			var y = new List<object>();
			for (int i = 0; i < Items.Count; ++i) {
				var item = Items[i];
				y.Add(((IStateManager)item).SaveViewState());
			}

			return new Pair(x, y);
		}

		/// <summary>
		/// 
		/// </summary>
		protected override void TrackViewState() {
			base.TrackViewState();

			for (int i = 0; i < Items.Count; ++i) {
				var item = Items[i];

				((IStateManager)item).TrackViewState();
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="data"></param>
		/// <param name="index"></param>
		/// <returns></returns>
		protected virtual MyListItem CreateListItem(object data, int index) {
			string dataTextField = this.DataTextField;
			string dataValueField = this.DataValueField;
			string dataGroupField = this.DataGroupField;
			string dataTooltipField = this.DataTooltipField;
			string dataTextFormatString = this.DataTextFormatString;

			var item = new MyListItem(index);

			if (!string.IsNullOrEmpty(dataTextField) || !string.IsNullOrEmpty(dataValueField)) {
				if (dataTextField.Length > 0) {
					item.Text = DataBinder.GetPropertyValue(data, dataTextField, dataTextFormatString);
				}
				if (dataValueField.Length > 0) {
					item.Value = DataBinder.GetPropertyValue(data, dataValueField, null);
				}
				if (dataGroupField.Length > 0) {
					item.Group = DataBinder.GetPropertyValue(data, dataGroupField, null);
				}
				if (dataTooltipField.Length > 0) {
					item.Tooltip = DataBinder.GetPropertyValue(data, dataTooltipField, null);
				}
			} else {
				if (!string.IsNullOrEmpty(dataTextFormatString)) {
					item.Text = string.Format(CultureInfo.CurrentCulture, dataTextFormatString, data);
				} else {
					item.Text = data.ToString();
				}
				item.Value = data.ToString();
			}

			return item;
		}

		/// <summary>
		/// 
		/// </summary>
		[Category("Behavior"), DefaultValue(false), Description("AutoPostBackControl_CausesValidation"), Themeable(false)]
		public virtual bool CausesValidation {
			get {
				object obj2 = this.ViewState["CausesValidation"];
				return ((obj2 != null) && ((bool)obj2));
			}
			set {
				this.ViewState["CausesValidation"] = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[Category("Behavior"), DefaultValue(""), Description("PostBackControl_ValidationGroup"), Themeable(false)]
		public virtual string ValidationGroup {
			get {
				string str = (string)this.ViewState["ValidationGroup"];
				if (str != null) {
					return str;
				}
				return string.Empty;
			}
			set {
				this.ViewState["ValidationGroup"] = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="writer"></param>
		protected override void RenderContents(HtmlTextWriter writer) {
			var groups = Items.GroupBy(item => item.Group)
				.Select(g => new {
					Title = g.Key,
					Items = g.ToList()
				})
				.ToArray();

			if (groups.Length == 0) {
				RenderEmpty(writer);
				return;
			}

			foreach (var group in groups) {
				var showTitle = true;

				if (groups.Length == 1 && string.IsNullOrEmpty(group.Title)) {
					showTitle = false;
				}

				if (showTitle) {
					writer.RenderBeginTag(HtmlTextWriterTag.Fieldset);
					if (!string.IsNullOrEmpty(group.Title)) {
						writer.RenderBeginTag(HtmlTextWriterTag.Legend);
						writer.WriteEncodedText(group.Title);
						writer.RenderEndTag();
					}
				}

				if (!ShowUnselected) {
					group.Items.RemoveAll(item => !item.Selected);
				}

				for (int i = 0; i < group.Items.Count; ++i) {
					var item = group.Items[i];

					RenderListItem(writer, item, i);

					if (i < group.Items.Count - 1) {
						RenderSeperator(writer, i);
					}
				}

				if (showTitle) {
					writer.RenderEndTag();
				}
			} // end of foreach.
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="writer"></param>
		protected virtual void RenderEmpty(HtmlTextWriter writer) {
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="writer"></param>
		/// <param name="index"></param>
		protected virtual void RenderSeperator(HtmlTextWriter writer, int index) {
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="writer"></param>
		/// <param name="item"></param>
		/// <param name="index"></param>
		protected abstract void RenderListItem(HtmlTextWriter writer, MyListItem item, int index);
	} // end of MyListControl.

	/// <summary>
	/// 
	/// </summary>
	[TypeConverter(typeof(ExpandableObjectConverter)), ParseChildren(true, "Text"), ControlBuilder(typeof(ListItemControlBuilder))]
	public sealed class MyListItem : IStateManager, IParserAccessor, IAttributeAccessor {
		private int m_id;

		private string m_text;

		private string m_value;

		private string m_group;

		private string m_tooltip;

		/// <summary>
		/// 
		/// </summary>
		public int Id {
			get {
				return m_id;
			}
			set {
				m_id = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public string Text {
			get {
				if (m_text == null) {
					return string.Empty;
				} else {
					return m_text;
				}
			}
			set {
				m_text = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public string Value {
			get {
				if (m_value == null) {
					return string.Empty;
				} else {
					return m_value;
				}
			}
			set {
				m_value = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public bool Enabled { get; set; }

		/// <summary>
		/// 
		/// </summary>
		public string Group {
			get {
				if (m_group == null) {
					return string.Empty;
				} else {
					return m_group;
				}
			}
			set {
				m_group = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public string Tooltip {
			get {
				if (m_tooltip == null) {
					return string.Empty;
				} else {
					return m_tooltip;
				}
			}
			set {
				m_tooltip = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public bool Selected { get; set; }

		/// <summary>
		/// 
		/// </summary>
		/// <param name="id"></param>
		public MyListItem(int id) {
			Enabled = true;

			m_id = id;
			m_text = string.Empty;
			m_value = string.Empty;
			m_group = string.Empty;
			m_tooltip = string.Empty;
			m_marked = false;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		public override int GetHashCode() {
			if (Value == null) {
				return 0;
			} else {
				return Value.GetHashCode();
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="obj"></param>
		/// <returns></returns>
		public override bool Equals(object obj) {
			if (obj == null) {
				return false;
			} else {
				var a = obj as MyListItem;
				return a.Value == this.Value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		public override string ToString() {
			return string.Format("Id = \"{5}\", Value = \"{0}\", Text = \"{1}\", Group = \"{2}\", Tooltip = \"{3}\", Selected = {4}",
				Value, Text, Group, Tooltip, Selected, Id);
		}

		#region IStateManager
		private bool m_marked;

		bool IStateManager.IsTrackingViewState {
			get { return m_marked; }
		}

		void IStateManager.LoadViewState(object state) {
			if (state != null) {
				if (state is Tuple<int, string, string, string, bool>) {
					var t = (Tuple<int, string, string, string, bool>)state;

					this.Id = t.Item1;
					this.Text = t.Item2;
					this.Value = t.Item3;
					this.Group = t.Item4;
					this.Enabled = t.Item5;
				}
			}
		}

		object IStateManager.SaveViewState() {
			return new Tuple<int, string, string, string, bool>(
				Id, Text, Value, Group, Enabled);
		}

		void IStateManager.TrackViewState() {
			m_marked = true;
		}

		#endregion

		#region IParserAccessor

		void IParserAccessor.AddParsedSubObject(object obj) {
			if (obj is LiteralControl) {
				this.Text = ((LiteralControl)obj).Text;
			} else {
				if (obj is DataBoundLiteralControl) {
					throw new HttpException("MyListItem cannot data bind");
				}
				throw new HttpException(string.Format("MyListItem can not have children of Type", obj.GetType()));
			}
		}

		#endregion

		private System.Web.UI.AttributeCollection m_attributes;

		/// <summary>
		/// 
		/// </summary>
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false)]
		public System.Web.UI.AttributeCollection Attributes {
			get {
				if (this.m_attributes == null) {
					this.m_attributes = new System.Web.UI.AttributeCollection(new StateBag(true));
				}
				return this.m_attributes;
			}
		}

		#region IAttributeAccessor

		string IAttributeAccessor.GetAttribute(string key) {
			return Attributes[key];
		}

		void IAttributeAccessor.SetAttribute(string key, string value) {
			Attributes[key] = value;
		}

		#endregion
	} // end of MyListItem.
}
